const { ethers } = require('ethers');
const { Badge } = require('../models');

class BlockchainService {
  constructor() {
    this.provider = new ethers.providers.JsonRpcProvider(
      process.env.POLYGON_RPC_URL || 'https://polygon-rpc.com'
    );
    
    // 只有当PRIVATE_KEY存在且不是默认值时才创建钱包实例
    if (process.env.PRIVATE_KEY && 
        process.env.PRIVATE_KEY !== 'your_private_key_here' && 
        process.env.PRIVATE_KEY.startsWith('0x')) {
      try {
        this.wallet = new ethers.Wallet(process.env.PRIVATE_KEY, this.provider);
      } catch (error) {
        console.warn('无法创建区块链钱包：', error.message);
        console.warn('将使用模拟模式运行徽章服务');
        this.wallet = null;
      }
    } else {
      console.log('区块链服务使用模拟模式 - 未配置私钥或使用了默认值');
      this.wallet = null;
    }
    
    // NFT合约ABI（简化版）
    this.contractABI = [
      "function mintBadge(address to, uint256 tokenId, string memory tokenURI) public",
      "function ownerOf(uint256 tokenId) public view returns (address)",
      "function tokenURI(uint256 tokenId) public view returns (string memory)",
      "function balanceOf(address owner) public view returns (uint256)",
      "function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256)"
    ];
  }

  // 铸造NFT徽章
  async mintNFTBadge(userAddress, activityId, badgeData) {
    try {
      // 如果没有配置区块链环境，直接在数据库中创建勋章记录
      if (!this.wallet || !process.env.NFT_CONTRACT_ADDRESS) {
        console.log('区块链未配置，使用模拟模式创建勋章...');
        
        // 生成模拟的token ID
        const tokenId = Date.now().toString() + Math.random().toString(36).substr(2, 9);
        
        // 创建数据库记录
        const badge = await Badge.create({
          user_id: badgeData.userId,
          activity_id: activityId,
          token_id: tokenId,
          contract_address: 'mock_contract_address',
          badge_name: badgeData.name,
          badge_description: badgeData.description,
          badge_image_url: badgeData.imageUrl,
          rarity: badgeData.rarity || 'common',
          attributes: badgeData.attributes || {},
          metadata_uri: `mock://metadata/${tokenId}`,
          status: 'minted',
          minted_at: new Date()
        });
        
        return {
          success: true,
          badge,
          transactionHash: `mock_tx_${tokenId}`,
          tokenId: tokenId
        };
      }

      // 原有的区块链逻辑
      const contract = new ethers.Contract(
        process.env.NFT_CONTRACT_ADDRESS,
        this.contractABI,
        this.wallet
      );

      // 生成唯一的token ID
      const tokenId = await this.generateTokenId(activityId, userAddress);
      
      // 上传元数据到IPFS或其他存储
      const metadataURI = await this.uploadMetadata(badgeData);
      
      // 创建数据库记录
      const badge = await Badge.create({
        user_id: badgeData.userId,
        activity_id: activityId,
        token_id: tokenId.toString(),
        contract_address: process.env.NFT_CONTRACT_ADDRESS,
        badge_name: badgeData.name,
        badge_description: badgeData.description,
        badge_image_url: badgeData.imageUrl,
        rarity: badgeData.rarity || 'common',
        attributes: badgeData.attributes || {},
        metadata_uri: metadataURI,
        status: 'minting'
      });

      // 执行区块链交易
      const tx = await contract.mintBadge(userAddress, tokenId, metadataURI);
      
      // 更新交易哈希
      await badge.update({
        transaction_hash: tx.hash
      });

      // 等待交易确认
      const receipt = await tx.wait();
      
      if (receipt.status === 1) {
        await badge.update({
          status: 'minted',
          minted_at: new Date()
        });
        
        return {
          success: true,
          badge,
          transactionHash: tx.hash,
          tokenId: tokenId.toString()
        };
      } else {
        await badge.update({ status: 'failed' });
        throw new Error('区块链交易失败');
      }
    } catch (error) {
      console.error('NFT铸造失败:', error);
      throw error;
    }
  }

  // 生成唯一的token ID
  async generateTokenId(activityId, userAddress) {
    const timestamp = Date.now();
    const hash = ethers.utils.keccak256(
      ethers.utils.defaultAbiCoder.encode(
        ['uint256', 'address', 'uint256'],
        [activityId, userAddress, timestamp]
      )
    );
    
    // 取哈希的前8字节作为token ID
    return ethers.BigNumber.from(hash).mod(ethers.BigNumber.from(2).pow(64));
  }

  // 上传元数据（模拟IPFS上传）
  async uploadMetadata(badgeData) {
    const metadata = {
      name: badgeData.name,
      description: badgeData.description,
      image: badgeData.imageUrl,
      attributes: badgeData.attributes || [],
      external_url: `${process.env.FRONTEND_URL}/badges/${badgeData.tokenId}`,
      animation_url: badgeData.animationUrl,
      background_color: badgeData.backgroundColor
    };

    // 在实际项目中，这里应该上传到IPFS
    // 现在返回一个模拟的URI
    const metadataString = JSON.stringify(metadata);
    const hash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(metadataString));
    
    return `ipfs://QmExample${hash.slice(2, 10)}`;
  }

  // 获取用户的NFT徽章
  async getUserBadges(userAddress) {
    try {
      if (!process.env.NFT_CONTRACT_ADDRESS) {
        // 如果没有配置合约地址，从数据库获取
        return await Badge.findAll({
          where: { user_id: userAddress },
          order: [['minted_at', 'DESC']]
        });
      }

      const contract = new ethers.Contract(
        process.env.NFT_CONTRACT_ADDRESS,
        this.contractABI,
        this.provider
      );

      const balance = await contract.balanceOf(userAddress);
      const badges = [];

      for (let i = 0; i < balance.toNumber(); i++) {
        const tokenId = await contract.tokenOfOwnerByIndex(userAddress, i);
        const tokenURI = await contract.tokenURI(tokenId);
        
        // 从数据库获取详细信息
        const badgeInfo = await Badge.findOne({
          where: { token_id: tokenId.toString() }
        });

        badges.push({
          tokenId: tokenId.toString(),
          tokenURI,
          ...badgeInfo?.toJSON()
        });
      }

      return badges;
    } catch (error) {
      console.error('获取用户徽章失败:', error);
      throw error;
    }
  }

  // 验证NFT所有权
  async verifyBadgeOwnership(tokenId, userAddress) {
    try {
      const contract = new ethers.Contract(
        process.env.NFT_CONTRACT_ADDRESS,
        this.contractABI,
        this.provider
      );

      const owner = await contract.ownerOf(tokenId);
      return owner.toLowerCase() === userAddress.toLowerCase();
    } catch (error) {
      console.error('验证徽章所有权失败:', error);
      return false;
    }
  }

  // 获取徽章元数据
  async getBadgeMetadata(tokenId) {
    try {
      const contract = new ethers.Contract(
        process.env.NFT_CONTRACT_ADDRESS,
        this.contractABI,
        this.provider
      );

      const tokenURI = await contract.tokenURI(tokenId);
      
      // 如果是IPFS URI，需要通过IPFS网关获取
      if (tokenURI.startsWith('ipfs://')) {
        const ipfsHash = tokenURI.replace('ipfs://', '');
        const response = await fetch(`https://ipfs.io/ipfs/${ipfsHash}`);
        return await response.json();
      }
      
      // 如果是HTTP URI，直接获取
      if (tokenURI.startsWith('http')) {
        const response = await fetch(tokenURI);
        return await response.json();
      }
      
      return null;
    } catch (error) {
      console.error('获取徽章元数据失败:', error);
      return null;
    }
  }

  // 生成徽章图片（基于活动信息）
  generateBadgeImage(activityData, rarity = 'common') {
    // 这里应该调用图片生成服务
    // 现在返回一个模拟的图片URL
    const rarityColors = {
      common: '#808080',
      rare: '#0080FF',
      epic: '#8000FF',
      legendary: '#FFD700'
    };
    
    const color = rarityColors[rarity] || rarityColors.common;
    
    return `https://api.dicebear.com/7.x/shapes/svg?seed=${activityData.title}&backgroundColor=${color.slice(1)}`;
  }

  // 检查网络状态
  async checkNetworkStatus() {
    try {
      const network = await this.provider.getNetwork();
      const blockNumber = await this.provider.getBlockNumber();
      
      return {
        connected: true,
        network: network.name,
        chainId: network.chainId,
        blockNumber
      };
    } catch (error) {
      return {
        connected: false,
        error: error.message
      };
    }
  }

  // 估算Gas费用
  async estimateGasFee(userAddress, activityId, badgeData) {
    try {
      if (!this.wallet) {
        return { gasPrice: '0', gasLimit: '0', estimatedCost: '0' };
      }

      const contract = new ethers.Contract(
        process.env.NFT_CONTRACT_ADDRESS,
        this.contractABI,
        this.wallet
      );

      const tokenId = await this.generateTokenId(activityId, userAddress);
      const metadataURI = 'ipfs://QmExample'; // 临时URI用于估算

      const gasLimit = await contract.estimateGas.mintBadge(
        userAddress,
        tokenId,
        metadataURI
      );

      const gasPrice = await this.provider.getGasPrice();
      const estimatedCost = gasLimit.mul(gasPrice);

      return {
        gasPrice: ethers.utils.formatUnits(gasPrice, 'gwei'),
        gasLimit: gasLimit.toString(),
        estimatedCost: ethers.utils.formatEther(estimatedCost)
      };
    } catch (error) {
      console.error('估算Gas费用失败:', error);
      return { gasPrice: '0', gasLimit: '0', estimatedCost: '0' };
    }
  }
}

module.exports = new BlockchainService(); 